package edu.ustb.aur.controller;

import edu.ustb.aur.chain.Chain;
import edu.ustb.aur.chain.ChainService;
import edu.ustb.aur.chain.interactive.ChainInteractiveService;
import edu.ustb.aur.myenum.ResultCodeEnum;
import edu.ustb.aur.result.Result;
import edu.ustb.aur.userpackage.User;
import edu.ustb.aur.userpackage.UserService;
import edu.ustb.aur.vo.CarControllerVo;
import edu.ustb.shellchainapi.shellchain.command.ShellChainException;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author ShiZhe
 * @create 2021-11-15 15:36
 * 用户前后端交互
 */
@Api(tags = "用户控制器")
@RestController
@RequestMapping("user")
@CrossOrigin
public class UserController {

    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    /**
     * 链类存储服务
     */
    @Autowired
    private ChainService chainService;

    /**
     * 资产链
     */
    @Autowired
    private ChainInteractiveService chainInteractiveServiceAsset = new ChainInteractiveService("OBJ");

    /**
     * 添加日志对象
     */
    private Logger log = LoggerFactory.getLogger(getClass());

    /**
     * 新建用户
     *
     * @param user 用户对象，不包含UserAddress字段，该字段通过链交易获得
     * @return Result
     */
    @ApiOperation(value = "createUser", notes = "新建用户")
    @PostMapping("createUser/{contractName}/{contractId}")
    public Result createUser(@ApiParam(name = "user", value = "用户对象", required = true) @RequestBody User user, @PathVariable String contractName, @PathVariable String contractId) throws ShellChainException {

        //上链参数
        HashMap<String, Object> attributes = new HashMap<>();
        // 唯一表示，生成一个hash值
        attributes.put("contractId", contractId);
        // 只给英文
        attributes.put("contractName", contractName);
        attributes.put("user", user);
        // 获取链交易id
//        String txId = chainInteractiveServiceAsset.sendToChain(
//                "1QLogU2pmCSne3NAWrfia9pfPmjHDBnkjMkM7q", 0, attributes);
        String txId = chainInteractiveServiceAsset.sendToChain(
                "18XEZTrTtqQVfDxVafcJoBd37xrtcBvH4Cs4yV", 0, attributes);

        // 测试专用，上链得到交易ID
        log.info("用户创建信息上链后得到的交易id为：" + txId);

        // chain实体类
        boolean contractIdIsExist = chainService.findContractIdIsExist(contractId);
        if (contractIdIsExist) {
            chainService.addContractTxIdList(contractId, txId);
        } else {
            Chain chain = new Chain();
            chain.setContractId(contractId);
            chain.setContractName(contractName);
            ArrayList<String> contractTxIdList = new ArrayList<>();
            contractTxIdList.add(txId);
            chain.setContractTxIdList(contractTxIdList);
            chainService.createChain(chain);
        }
        // 设置UserAddress
        user.setUserAddress(txId);
        // 创建user
        if (this.userService.createUser(user)){
            // 测试专用，用户创建成功，输出成功信息
            log.info("用户创建成功，用户对象实例为：" + user);
            return Result.ok();
        }else {
            log.error("用户创建失败！！！");
            return Result.fail(Result.build(user, ResultCodeEnum.FAIL));
        }
    }

    /**
     * 转账
     *
     * @return Result
     */
    @ApiOperation(value = "transfer", notes = "转账")
    @PostMapping("transfer")
    public Result transfer(@RequestBody CarControllerVo carControllerVo) throws ShellChainException {

        //上链参数
        HashMap<String, Object> attributes = new HashMap<>();
        // 唯一表示，生成一个hash值
        attributes.put("contractId", carControllerVo.getContractId());
        // 只给英文
        attributes.put("contractName", carControllerVo.getContractName());
        attributes.put("userAddressFrom", carControllerVo.getUserAddressFrom());
        attributes.put("userAddressIn", carControllerVo.getUserAddressIn());
        attributes.put("money", carControllerVo.getMoney());
        // 获取链交易id
        String txId = chainInteractiveServiceAsset.sendToChain(
                "18XEZTrTtqQVfDxVafcJoBd37xrtcBvH4Cs4yV", 0, attributes);

        // 测试专用，上链得到交易ID
        log.info("用户创建信息上链后得到的交易id为：" + txId);

        // chain实体类
        boolean contractIdIsExist = chainService.findContractIdIsExist(carControllerVo.getContractId());
        if (contractIdIsExist) {
            chainService.addContractTxIdList(carControllerVo.getContractId(), txId);
        } else {
            Chain chain = new Chain();
            chain.setContractId(carControllerVo.getContractId());
            chain.setContractName(carControllerVo.getContractName());
            ArrayList<String> contractTxIdList = new ArrayList<>();
            contractTxIdList.add(txId);
            chain.setContractTxIdList(contractTxIdList);
            chainService.createChain(chain);
        }
        // 转出
        boolean b = userService.transferOut(carControllerVo.getUserAddressFrom(), carControllerVo.getMoney());
        boolean b1 = userService.transferIn(carControllerVo.getUserAddressIn(), carControllerVo.getMoney());
        if (b && b1) {
            return Result.ok();
        } else {
            return Result.fail();
        }
    }

    /**
     * 根据用户地址得到user对象
     *
     * @param userAddress 用户hash地址
     * @return Result
     */
    @ApiOperation(value = "findUser", notes = "根据用户地址得到user对象")
    @GetMapping("findUser/{userAddress}")
    public Result findUser(@ApiParam(name = "userAddress", value = "用户hash地址", required = true) @PathVariable String userAddress){
        User user = userService.findUser(userAddress);
        if (user == null){
            log.error("查询失败，数据库中无该用户地址："+ userAddress);
            return Result.fail(Result.build(null,ResultCodeEnum.DATA_ERROR));
        }
        log.info("用户查询操作成功，返回的用户对象为："+ user.toString());
        return Result.ok(user);
    }

    /**
     * 添加资产hash集合
     *
     * @param userAddress 用户hash地址
     * @param assetId 资产hash地址
     * @return Result
     */
    @ApiOperation(value = "addAssetList", notes = "添加资产hash集合")
    @PostMapping("assetList/add/{userAddress}/{assetId}")
    public Result addAssetList(@ApiParam(name = "userAddress", value = "用户hash地址", required = true) @PathVariable String userAddress,
                               @ApiParam(name = "assetId", value = "资产hash地址", required = true) @PathVariable String assetId){
        if (userService.addAssetList(userAddress,assetId)){
            return Result.ok();
        }else {
            return Result.fail(Result.build(userAddress,ResultCodeEnum.FAIL));
        }
    }

    /**
     * 删除资产hash集合
     *
     * @param userAddress 用户hash地址
     * @param assetId 资产hash地址
     * @return Result
     */
    @ApiOperation(value = "deleteAssetList", notes = "删除资产hash集合")
    @DeleteMapping("/assetList/delete/{userAddress}/{assetId}")
    public Result deleteAssetList(@ApiParam(name = "userAddress", value = "用户hash地址", required = true) @PathVariable String userAddress,
                                  @ApiParam(name = "assetId", value = "资产hash地址", required = true) @PathVariable String assetId){
        if (userService.deleteAssetList(userAddress,assetId)){
            return Result.ok();
        }else {
            return Result.fail(Result.build(assetId,ResultCodeEnum.FAIL));
        }
    }

    /**
     * 查询用户涉及的资产集合
     *
     * @param userAddress 用户hash地址
     * @return Result
     */
    @ApiOperation(value = "findAssetList", notes = "查询用户涉及的资产集合")
    @GetMapping("/assetList/find/{userAddress}")
    public Result findAssetList(@ApiParam(name = "userAddress", value = "用户hash地址", required = true) @PathVariable String userAddress){
        List<String> assetList = userService.findAssetList(userAddress);
        if (assetList == null){
            return Result.fail(Result.build(null,ResultCodeEnum.DATA_ERROR));
        }
        return Result.ok(assetList);
    }

    /**
     * 查询所有用户的所有信息
     * @return
     */
    @ApiOperation(value = "findAllUser", notes = "查询所有用户的所有信息")
    @GetMapping("findAllUser")
    public Result findAllUser() {
        // 调用service方法
        List<User> userList = userService.list();
        return Result.ok(userList);
    }
}
